const fs = require('fs');
const path = require('path');
const https = require('https');
import { createHash } from 'crypto';
import { EventEmitter } from 'events';
import { join } from 'path';
import { URL } from 'url';
import { findAllFiles } from '../utils/FileUtil';
import { TempPath } from './Tinypng';

const root = './',
    exts = ['.jpg', '.png'],
    max = 5200000; // 5MB == 5242848.754299136

export function compressDir(dirPath: string, callback: Function, logFunc: (msg) => void, excludeHash?: any) {
    let imgList = findAllFiles(dirPath, [".png", ".jpg"], excludeHash);
    let failHash = {};
    let total = imgList.length;
    let workingNum = 0;
    function compressNext(success?: boolean, filePath?: string) {
        if (filePath) {
            workingNum--;
            logFunc(`压缩[${success ? "成功" : "失败"}]---${filePath}`);
            if (!success) {
                if (!failHash[filePath] || failHash[filePath] < 5) {
                    failHash[filePath] = Number(failHash[filePath] || 0) + 1;
                    imgList.push(filePath);
                }
            } else {
                delete failHash[filePath];
            }
        }
        if (imgList.length > 0) {
            logFunc("开始压缩---" + imgList[0]);
            workingNum++;
            compress(imgList.shift(), compressNext);
        } else {
            if (workingNum == 0) {
                let failList = [];
                for (let file in failHash) {
                    failList.push(file);
                }

                logFunc(`压缩完成,成功${total - failList.length},失败${failList.length}\n失败列表:${failList.join("\n")}`);
                callback && callback();
            }
        }
    }
    compressNext();
}

export function compress(filePath: string, callback: (success: boolean, filePath: string) => void) {
    let tiny = new TinyHtml();
    tiny.on("error", (err) => {
        console.error(err);
        callback && callback(false, filePath);
    });
    tiny.on("complete", () => {
        callback && callback(true, filePath);
    })
    tiny.compress(filePath);
}

class TinyHtml extends EventEmitter {
    private _tryCount: number;
    private _options: any;
    constructor() {
        super();
        this._tryCount = 0;
    }

    compress(filePath: string) {
        fs.stat(filePath, (err, stats) => {
            if (err) {
                this.emit("error", err);
                return;
            }
            if (stats.size <= max && stats.isFile() && exts.indexOf(path.extname(filePath)) != -1) {
                this.fileUpload(filePath); // console.log('可以压缩：' + file);
            } else {
                this.emit("error", "文件不符合条件");
            }
        });
    }

    fileUpload(img) {
        this._options = {
            method: 'POST',
            hostname: 'tinypng.com',
            path: '/web/shrink',
            headers: {
                rejectUnauthorized: false,
                'Postman-Token': Date.now(),
                'Cache-Control': 'no-cache',
                'Content-Type': 'application/x-www-form-urlencoded',
                'User-Agent':
                    'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
            }
        };
        let sourceData = fs.readFileSync(img);
        let md5 = createHash('md5');
        md5.update(sourceData);
        let md5Str = md5.digest('hex');
        let fileType = path.extname(img);
        let tempFilePath = join(TempPath, md5Str) + fileType;
        if (fs.existsSync(tempFilePath)) {
            fs.copyFileSync(tempFilePath, img);
            this.emit("complete");
            return;
        }
        var req = https.request(this._options, (res) => {
            res.on('data', buf => {
                let obj = JSON.parse(buf.toString());
                if (obj.error) {
                    console.log(`[${img}]：压缩失败！报错：${obj.message}`);
                    this._tryCount++;
                    if (this._tryCount < 3) {
                        setTimeout(() => {
                            this.fileUpload(img);
                        }, 10000);
                    } else {
                        this.emit("error", `[${img}]：压缩失败！报错：${obj.message}`);
                    }
                } else {
                    this.fileUpdate(img, obj, tempFilePath);
                }
            });
        });

        req.write(sourceData, 'binary');
        req.on('error', e => {
            this.emit("error", e);
        });
        req.end();
    }

    fileUpdate(imgpath, obj, tempFilePath: string) {
        let options = new URL(obj.output.url);
        let req = https.request(options, res => {
            let body = '';
            res.setEncoding('binary');
            res.on('data', function (data) {
                body += data;
            });

            res.on('end', () => {
                fs.writeFile(imgpath, body, 'binary', err => {
                    if (err) {
                        this.emit("error", err);
                        return;
                    }
                    console.log(
                        `[${imgpath}] \n 压缩成功，原始大小-${obj.input.size}，压缩大小-${
                        obj.output.size
                        }，优化比例-${obj.output.ratio}`
                    );
                    fs.copyFileSync(imgpath, tempFilePath);
                    this.emit("complete");
                });
            });
        });
        req.on('error', e => {
            this.emit("error", e);
        });
        req.end();
    }
}

